﻿using System;
using System.Collections.ObjectModel;
using System.Linq;
using System.Windows;
using System.Windows.Input;
using Wizardry;
using Microsoft.Practices.Prism.Commands;
using Microsoft.Practices.Unity;
using Microsoft.Practices.Prism.Logging;

namespace Wizardry
{
    public class WizardViewModel : ViewModelBase, IWizardViewModel
    {
        #region Fields

        private IUnityContainer container;
        private IWizardController wizardController;

        #endregion

        #region Properties

        public ICommand BackCommand { get; private set; }

        public ICommand NextCommand { get; private set; }

        public IWizardPageView CurrentPage
        {
            get { return (IWizardPageView)GetValue(CurrentPageProperty); }
            set { SetValue(CurrentPageProperty, value); }
        }

        // Using a DependencyProperty as the backing store for CurrentPage.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty CurrentPageProperty =
            DependencyProperty.Register("CurrentPage", typeof(IWizardPageView), typeof(WizardViewModel), new UIPropertyMetadata(null));

        public string ForwardButtonText
        {
            get { return (string)GetValue(ForwardButtonTextProperty); }
            set { SetValue(ForwardButtonTextProperty, value); }
        }

        // Using a DependencyProperty as the backing store for ForwardButtonText.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty ForwardButtonTextProperty =
            DependencyProperty.Register("ForwardButtonText", typeof(string), typeof(WizardViewModel), new UIPropertyMetadata(null));

        public ObservableCollection<WizardNavigationHistoryDescriptor> NavigationHistory
        {
            get { return (ObservableCollection<WizardNavigationHistoryDescriptor>)GetValue(NavigationHistoryProperty); }
            set { SetValue(NavigationHistoryProperty, value); }
        }

        // Using a DependencyProperty as the backing store for NavigationHistory.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty NavigationHistoryProperty =
            DependencyProperty.Register("NavigationHistory", typeof(ObservableCollection<WizardNavigationHistoryDescriptor>), typeof(WizardViewModel), new UIPropertyMetadata(null));

        public string Title
        {
            get { return (string)GetValue(TitleProperty); }
            set { SetValue(TitleProperty, value); }
        }

        // Using a DependencyProperty as the backing store for Title.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty TitleProperty =
            DependencyProperty.Register("Title", typeof(string), typeof(WizardViewModel), new UIPropertyMetadata(null));

        public WizardResult WizardResult
        {
            get { return (WizardResult)GetValue(WizardResultProperty); }
            set { SetValue(WizardResultProperty, value); }
        }

        // Using a DependencyProperty as the backing store for WizardResult.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty WizardResultProperty =
            DependencyProperty.Register("WizardResult", typeof(WizardResult), typeof(WizardViewModel), new PropertyMetadata(WizardResult.None));

        #endregion

        #region Constructors

        public WizardViewModel(IUnityContainer container)
        {
            this.container = container;

            this.BackCommand = new DelegateCommand(this.HandleBackCommand, this.CanNavigateBack);
            this.NextCommand = new DelegateCommand(this.HandleNextCommand, this.CanNavigateForward);

            this.NavigationHistory = new ObservableCollection<WizardNavigationHistoryDescriptor>();
        }

        #endregion

        #region IWizardViewModel Members

        public void SetController(IWizardController controller)
        {
            this.wizardController = controller;

            if (this.wizardController == null)
            {
                throw new ArgumentNullException("The supplied controller is null");
            }

            if (this.wizardController.NavigationHistory != null)
            {
                this.wizardController.NavigationHistory.CollectionChanged += NavigationHistory_CollectionChanged;
            }

            this.wizardController.InitialisePages();

            this.CurrentPage = this.wizardController.NavigateForward();

            this.wizardController.CanNavigateChanged += wizardController_CanNavigateChanged;

            this.Title = this.wizardController.Title;

            this.RefreshCommands();
        }

        #endregion

        #region Event Handlers

        void wizardController_CanNavigateChanged(object sender, EventArgs e)
        {
            this.RefreshCommands();
        }

        void NavigationHistory_CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
        {
            switch (e.Action)
            {
                case System.Collections.Specialized.NotifyCollectionChangedAction.Add:
                    if (e.NewItems != null)
                    {
                        foreach (var item in e.NewItems.OfType<WizardNavigationHistoryDescriptor>())
                        {
                            this.NavigationHistory.Add(item);
                        }
                    }
                    break;
                case System.Collections.Specialized.NotifyCollectionChangedAction.Move:
                    break;
                case System.Collections.Specialized.NotifyCollectionChangedAction.Remove:
                    if (e.OldItems != null)
                    {
                        foreach (var item in e.OldItems.OfType<WizardNavigationHistoryDescriptor>())
                        {
                            this.NavigationHistory.Remove(item);
                        }
                    }
                    break;
                case System.Collections.Specialized.NotifyCollectionChangedAction.Replace:
                    break;
                case System.Collections.Specialized.NotifyCollectionChangedAction.Reset:
                    break;
                default:
                    break;
            }
        }

        #endregion

        #region Private Methods

        private bool CanNavigateBack()
        {
            return this.wizardController.CanNavigateBackward;
        }

        private bool CanNavigateForward()
        {
            return this.wizardController.CanNavigateForward || this.wizardController.CanFinish;
        }

        private void HandleBackCommand()
        {
            this.CurrentPage = this.wizardController.NavigateBackward();

            this.RefreshCommands();
        }

        private void HandleNextCommand()
        {
            if (this.wizardController.CanFinish)
            {
                this.wizardController.Finish();

                this.WizardResult = WizardResult.Finish;
            }
            else
            {
                this.CurrentPage = this.wizardController.NavigateForward();
            }

            this.RefreshCommands();
        }

        private void RefreshCommands()
        {
            this.ForwardButtonText = this.wizardController.CanFinish ? Properties.Resources.Finish : Properties.Resources.Next;

            ((DelegateCommand)this.BackCommand).RaiseCanExecuteChanged();
            ((DelegateCommand)this.NextCommand).RaiseCanExecuteChanged();
        }

        #endregion
    }
}
